package accs.gui.logic;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.List;

import org.apache.http.HttpHost;

import accs.model.Account;
import accs.model.AccountChecker;
import accs.model.Context;
import accs.model.UserPasswordPair;
import accs.model.io.UserPasswordReader;

public class AccountCheckerTask extends CheckerTask {
	private List<UserPasswordPair> pairs;
	private BufferedWriter writer;
	private AccountChecker checker;
	private int threadNumber=1;
	
	private int currentPair=-1;
	private boolean running=false;
	
	private int working=0;
	private int notWorking=0;
	
	private String newLine="\n";
	
	private String infoText="";
	
	private List<HttpHost> proxyList=null;
	private int currentProxy=-1;
	
	public AccountCheckerTask(String infoText) {
		this.infoText=infoText;
	}
	
	public void loadUserPasswordPairs(UserPasswordReader reader) throws IOException {
		this.pairs=reader.readAll();
	}
	
	public void setUserPasswordPairs(List<UserPasswordPair> pairs) {
		this.pairs=pairs;
	}
	
	public void setOutput(Writer writer) {
		this.writer=new BufferedWriter(writer);
	}
	
	public void setOutput(File file) throws UnsupportedEncodingException, FileNotFoundException {
		this.writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"utf-8"));
	}
	
	public void setAccountChecker(AccountChecker checker) {
		this.checker=checker;
	}
	
	public void setNumberOfThreads(int number) {
		this.threadNumber=number;
	}
	
	public void setNewLine(String newLine) {
		this.newLine = newLine;
	}
	
	public void setProxyList(List<HttpHost> list) {
		this.proxyList=list;
	}

	private synchronized UserPasswordPair giveData() {
		currentPair++;
		if(currentPair<pairs.size()) {
			return pairs.get(currentPair);
		} else {
			return null;
		}
	}
	
	private synchronized HttpHost giveProxy() {
		currentProxy=(currentProxy+1) % proxyList.size();
		return proxyList.get(currentProxy);
	}
	
	private synchronized void putWorking(Account acc) throws IOException {
		working++;
		writer.write(acc.toString());
		writer.write(newLine);
		writer.flush();
		fireProgressUpdate(working, notWorking, pairs.size());
	}
	
	private synchronized void putNotWorking() {
		notWorking++;
		fireProgressUpdate(working, notWorking, pairs.size());
	}
	
	public void start() {
		fireInfoTextUpdate(infoText);
		
		if(!running) {
			running=true;
			for(int i=0; i<threadNumber; i++) {
				new Worker().start();
			}
		}
	}
	
	public void stop() {
		running=false;
	}
	
	private class Worker extends Thread {
		public void run() {
			while(running) {
				UserPasswordPair pair=giveData();
				if(pair==null) return;
				
				try {
					Context ctx=new Context();
					if(proxyList!=null) ctx.setProxy(giveProxy());
					Account acc=checker.login(pair.getUsername(),pair.getPassword(),ctx);
					
					if(acc==null) {
						putNotWorking();
					} else {
						putWorking(acc);
					}
					
				} catch (Exception e) {
					System.out.println(e.toString());
					putNotWorking();
				}
				
			}
		}
	}

	public boolean isRunning() {
		return running;
	}

	public int getTotal() {
		return pairs.size();
	}
	
	public void close() throws IOException {
		writer.close();
	}

	public String getTitle() {
		return infoText;
	}
}